/*
 * =====================================================================================
 *
 *       Filename:  main.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2020年02月25日 16时22分41秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <pcap.h>
#include "util_net.h"
#include "util_debug.h"

void pcap_cb(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
    struct ethhdr *ethh = (struct ethhdr *)packet;
    if(NULL == ethh) {
        debug_err("%s(): ethhdr is NULL\n", __func__);
    }
  
    switch(ntohs(ethh->h_proto)) {
    case ETHERTYPE_IP:
        {
            struct iphdr *iph = (struct iphdr *)(packet + (sizeof(struct ethhdr)));
            char *protocol = "";
            switch(iph->protocol) {
                case IPPROTO_TCP:
                    protocol = "TCP";
                    break;
                case IPPROTO_UDP:
                    protocol = "UDP";
                    break;
                case IPPROTO_ICMP:
                    protocol = "ICMP";
                    break;
                default:
                    break;
            }

            debug_print("[%s]:"IP_STR_FMT"("MAC_STR_FMT") --> "IP_STR_FMT"("MAC_STR_FMT")\n",
                    protocol,
                    IP_STR_ARG(&(iph->saddr)), MAC_STR_ARG(ethh->h_source),
                    IP_STR_ARG(&(iph->daddr)), MAC_STR_ARG(ethh->h_dest));
            break;
        }
    case ETHERTYPE_ARP:
        {
            /* 运维不占IP:在制定接口只能手动arp request或者gratituios arp */ 
            struct arphdr *arph = (struct arphdr *)(packet + sizeof(struct ethhdr));
            if(ntohs(arph->ar_op) != ARPOP_REQUEST) {
                debug_print("Not Arp Reques\n");
                break;
            }

            uint32_t sender_ip = 0;
            uint32_t target_ip = 0;
            uint8_t sender_mac[6] = {0};
            uint8_t target_mac[6] = {0};

            uint8_t *arp_data = (uint8_t *)(((uint8_t *)arph) + sizeof(struct arphdr));
            memcpy(sender_mac, arp_data, 6);
            memcpy(&sender_ip, arp_data + 6, 4);
            memcpy(target_mac, arp_data + 6 + 4, 6);
            memcpy(&target_ip, arp_data + 6 + 4 + 6, 4);

            debug_print("[ARP REQ]:"IP_STR_FMT"("MAC_STR_FMT") Ask Who Has "IP_STR_FMT"("MAC_STR_FMT")\n",
                        IP_STR_ARG(&sender_ip), MAC_STR_ARG(sender_mac),
                        IP_STR_ARG(&target_ip), MAC_STR_ARG(target_mac));
            break;
        }
    default:
        //debug_print("%s(): Do Not Parse ETH Proto %d For Now\n", __func__, ntohs(ethh->h_proto));
        break;
    }
}


int main(int argc, char **argv)
{
    char ebuf[PCAP_ERRBUF_SIZE] = {0};
    pcap_t *pcap = pcap_open_live("ens33", 65535, 0, 1000, ebuf);
    if(NULL == pcap) {
        debug_err("%s: %s\n", argv[0], ebuf);
        return -1;
    }

    struct pcap_pkthdr packet;

    int cnt = 0;
    while(1) {
        u_char *flag = pcap_next(pcap, &packet);
        if(flag) {
            cnt++;
            pcap_loop(pcap, 1, pcap_cb, NULL);
        }
    }
    
    pcap_close(pcap);

    return 0;
}

